package it.unicam.cs.cosy.bioshape.gui;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicButtonUI;

/**
 * Revisited {@code JTabbedPane} to add functionalities of closable tabs.
 * 
 * @author Federico Buti
 */
public class ClosableTabbedPane extends JTabbedPane {

	class TabClosableTitle extends JPanel implements ActionListener {

		/** generated serial id generated from eclipse */
		private static final long serialVersionUID = -2978722065488703847L;

		JLabel label;

		TabClosableTitle(String title) {
			setOpaque(false);
			setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
			setFocusable(false);
			// the label takes obviously the same name of the created dashboard
			label = new JLabel(title);
			label.setOpaque(false);
			label.setFocusable(false);
			// add more space between the label and the button
			label.setBorder(BorderFactory.createEmptyBorder(1, 0, 0, 0));
			// closing button
			JButton button = new JButton();
			button.setPreferredSize(new Dimension(14, 14));
			button.setToolTipText("Close simulation");
			// Make the button looks the same for all Laf's
			button.setUI(new BasicButtonUI());
			// Make it transparent
			button.setContentAreaFilled(false);
			// Make it not focusable
			button.setFocusable(false);
			// delete borders...
			button.setBorder(BorderFactory.createEmptyBorder(4, 3, 0, 0));
			// Making nice rollover effect
			button.setRolloverEnabled(true);
			// Set the image (also the pressed icon)
			ImageIcon image = new ImageIcon(
					Monitor.class.getResource("images/close16.png"));
			button.setIcon(image);
			button.setPressedIcon(new ImageIcon(Monitor.class
					.getResource("images/close16pressed.png")));
			// handler for closing action
			button.addActionListener(this);
			// composing...
			add(label);
			add(button);
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			// gain focus for THIS tab!
			int in = indexOfTabComponent(TabClosableTitle.this);
			setSelectedIndex(in);
			// never remove the reference to the external class or the wrong
			// "remove" is called
			if (verifySaving(getSelectedComponent()))
				ClosableTabbedPane.this.remove(getSelectedIndex());
		}

		void setTitle(String title) {
			label.setText(title);
		}

		void getTitle() {
			label.getText();
		}

		/**
		 * Checks if the current selected board has already been saved
		 * 
		 * @return <code>true</code> if already saved, <code>false</code>
		 *         otherwise
		 */
		private boolean verifySaving(DashBoard d) {
			if (!d.isDirtyBit())
				return true;
			// else...
			int returnValue = JOptionPane.showConfirmDialog(
					ClosableTabbedPane.this,
					"Save simulation " + "\"" + d.getTitle() + "\" ?", "Save",
					JOptionPane.YES_NO_CANCEL_OPTION);
			// switch for the three buttons...
			switch (returnValue) {
			case JOptionPane.CANCEL_OPTION:
				return false;
			case JOptionPane.NO_OPTION:
				return true;
			default:
				return IOHandler.save(d, false);
			}
		}

	}

	/** generated serial id generated from eclipse */
	private static final long serialVersionUID = -6468838658333862621L;

	/** internal number for new "untitled" panels */
	private int index = 0;

	/**
	 * Creates a new closable tabbed pane.
	 * 
	 * @param position
	 *            chosen position of the tab buttons
	 * @param policy
	 *            the way tabs are scrolled when they do not fit in the screen
	 */
	public ClosableTabbedPane(int position, int policy) {
		super(position, policy);
		// this.addTab();
		this.setFocusable(false);
	}

	/**
	 * Adds a new tab with the default title "untitled" plus an incremental
	 * index to distinguish subsequently created tabs.
	 */
	void addTab(Monitor m) {
		// creates the new dashboard given the title
		DashBoard newDash = new DashBoard(null, m);
		newDash.setDirtyBit(true);
		newDash.setTitle("untitled" + index + ".xml");
		// calls the metodo that adds an already created dashboard
		addTab(newDash);
		// increment index for the next "generic" tab
		index++;
	}

	/**
	 * Adds a new tab setting it into the passed <code>DashBoard</code>. Title
	 * is taken from the latter object.
	 * 
	 * @param db
	 *            <code>DashBoard</code> object to insert in the newly created
	 *            tab
	 */
	void addTab(DashBoard db) {
		// adds the loaded tab...
		addTab(db.getTitle(), null, db, db.getTitle());
		// sets the new tab title...
		int in = indexOfComponent(db);
		setTabComponentAt(in, new TabClosableTitle(db.getTitle()));
		// sets the "focus"...
		db.setVisible(true);
		db.requestFocusInWindow();
		setSelectedIndex(in);
	}

	/**
	 * Adds a new tab with the passed title. Constructor that takes a
	 * <code>DashBoard</code> is called after a new object of this type is
	 * created with title equal to the passed parameter.
	 * 
	 * @param file
	 *            file to open in the tab
	 */
	void addTab(File file, Monitor m) {
		// creates the new dashboard given the title
		DashBoard newDash = new DashBoard(file, m);
		newDash.setTitle(file.getName());
		// calls the method that adds an already created dashboard
		addTab(newDash);
	}

	@Override
	public DashBoard getSelectedComponent() {
		if (super.getSelectedComponent() instanceof DashBoard)
			return (DashBoard) (super.getSelectedComponent());
		return null;
	}

	@Override
	public TabClosableTitle getTabComponentAt(int index) {
		return (TabClosableTitle) super.getTabComponentAt(index);
	}

	@Override
	public void setTitleAt(int index, String title) {
		((TabClosableTitle) super.getTabComponentAt(index)).label
				.setText(title);
	}

	/**
	 * Removes the selected tab at the selected index. Generates also a new tab
	 * if all the tabs are removed. Selected tool is saved to pass it during new
	 * tab creation.
	 */
	@Override
	public void remove(int index) {
		super.remove(index);
		if (this.getTabCount() == 1) {
			// going up to the MonitorGUI object
			((Monitor) ClosableTabbedPane.this.getParent().getParent()
					.getParent().getParent().getParent()).doOperations("new");
			transferFocus();
		}
	}

	// @Override
	// public void stateChanged(ChangeEvent e) {
	// if (getTabCount() == 0)
	// return;
	// // getSelectedComponent().requestFocusInWindow();
	// }
}